package org.zookeeper.examples.command.overview;

import java.io.IOException;
import java.util.Arrays;
import org.apache.zookeeper.AsyncCallback.StatCallback;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

/**
 * 主要演示使用默认watcher与使用特定的watcher的区别
 *
 * @author slydm
 */
public class SingleWatchDemo {

  public static void main(String[] args) throws IOException, InterruptedException {
    /**
     *
     *  使用带Watch参数初始时, 该watcher成为默认watcher.
     *  zookeeper中所有可设置watcher的方法再不指定watch的情况下都使用该watcher.
     *  因此回调通知也是在该watch的#process()方法.
     *  比如以下几种试注册watch时没指定具体的watcher就会使用默认的watcher.
     *  <pre>
     * zooKeeper.exists("/d", true, this, null);
     * zooKeeper.exists("/a", true, this, null);
     * zooKeeper.exists("/b", true, this, null);
     * zooKeeper.exists("/c", true, this, null);</pre>
     *
     */

//    useDefaultWatcher();
    notUseDefaultWatcher();

    Thread.sleep(500000);
  }

  private static void useDefaultWatcher() throws IOException {
    ZooKeeper zooKeeper = new ZooKeeper("localhost:2181", 3000,
        new B());

    // 给节点注册watch, 使用默认的watcher
    zooKeeper.exists("/watch", true, null, true);
    zooKeeper.exists("/a", true, null, null);
    zooKeeper.exists("/b", true, null, null);
    zooKeeper.exists("/c", true, null, null);
  }

  private static void notUseDefaultWatcher() throws IOException {
    /*不设置默认watch*/
    ZooKeeper zooKeeper = new ZooKeeper("localhost:2181", 3000, null);
    new A(zooKeeper, "/watch");
  }


  static class B implements Watcher {


    /**
     * 这个方法实现只打印了事件的类型与znode路径, 没在重新注册watch, 因此每个被监视的znode事件只会接收到一次
     *
     * @param event
     */
    @Override
    public void process(WatchedEvent event) {
      System.out.println("B : " + event.getType() + " : path: " + event.getPath());
    }
  }

  static class A implements Watcher, StatCallback {

    private ZooKeeper zooKeeper;
    private String znode;
    private byte[] prevData;

    public A(ZooKeeper zooKeeper, String znode) {
      this.zooKeeper = zooKeeper;
      this.znode = znode;

      zooKeeper.exists(znode, this, this, null);
    }

    @Override
    public void process(WatchedEvent event) {
      System.out.println(Thread.currentThread().getName() + " : A : process: " + event);
      if (znode.equals(event.getPath())) {
        zooKeeper.exists(znode, this, this, null);
      }
    }

    @Override
    public void processResult(int rc, String path, Object ctx, Stat stat) {
      System.out.println(Thread.currentThread().getName() + ": processResult: " + rc);
      try {
        byte[] data = zooKeeper.getData(znode, false, null);
        if (data != null && !Arrays.equals(data, prevData)) {
          System.out.println(new String(data));
          prevData = data;
        }
      } catch (KeeperException e) {
        e.printStackTrace();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
}
